package self.zhangkang.chart.tools

import java.math.BigDecimal

/**
 * @author : Android-张康
 * created on: 2023/6/8 14:40
 * description: 数字格式化工具类
 */
object NumberFormatUtils {
    /**
     * 万亿
     */
    private const val TRILLION = 1000000000000L

    /**
     * 亿
     */
    private const val BILLION = 100000000

    /**
     * 万
     */
    private const val TEN_THOUSAND = 10000

    /**
     * 百
     */
    private const val HUNDRED = 100

    /**
     * 万亿
     */
    private val BIG_DECIMAL_TRILLION = BigDecimal(TRILLION)

    /**
     * 亿
     */
    private val BIG_DECIMAL_BILLION = BigDecimal(BILLION)

    /**
     * 万
     */
    private val BIG_DECIMAL_TEN_THOUSAND = BigDecimal(TEN_THOUSAND)

    /**
     * 百
     */
    val BIG_DECIMAL_HUNDRED = BigDecimal(HUNDRED)

    /**
     * 默认值
     */
    private val DEFAULT_VALUE = "0.00"

    /**
     * 将文字转为 [BigDecimal]
     *
     * @param number 需要格式化的数字
     */
    fun toBigDecimal(number: String?): BigDecimal? {
        if (number.isNullOrEmpty()) {
            return null
        }
        return try {
            BigDecimal(number)
        } catch (e: NumberFormatException) {
            null
        }
    }

    /**
     * 数字格式化
     *
     * @param number 需要格式化的数字
     * @param newScale 需要保留的小数位数
     */
    fun format(number: Float, newScale: Int = 2): String {
        return format(number.toString(), newScale)
    }

    /**
     * 数字格式化
     *
     * @param number 需要格式化的数字
     * @param newScale 需要保留的小数位数
     */
    fun format(number: Double, newScale: Int = 2): String {
        return format(number.toString(), newScale)
    }

    /**
     * 数字格式化
     *
     * @param number 需要格式化的数字
     * @param newScale 需要保留的小数位数
     */
    fun format(number: String?, newScale: Int = 2): String {
        val bigDecimal = toBigDecimal(number) ?: return DEFAULT_VALUE
        return format(bigDecimal, newScale)
    }

    /**
     * 数字格式化
     *
     * @param number 需要格式化的数字
     * @param newScale 需要保留的小数位数
     */
    fun format(number: BigDecimal, newScale: Int = 2): String {
        return number.setScale(newScale, BigDecimal.ROUND_HALF_UP)
            .toPlainString()
    }

    /**
     * 数字格式化。去除末尾的 0
     *
     * @param number 需要格式化的数字
     * @param newScale 需要保留的小数位数
     */
    fun formatStripTrailingZeros(number: Float, newScale: Int = 2): String {
        return formatStripTrailingZeros(number.toString(), newScale)
    }

    /**
     * 数字格式化。去除末尾的 0
     *
     * @param number 需要格式化的数字
     * @param newScale 需要保留的小数位数
     */
    fun formatStripTrailingZeros(number: String, newScale: Int = 2): String {
        return BigDecimal(number)
            .setScale(newScale, BigDecimal.ROUND_HALF_UP)
            .stripTrailingZeros()
            .toPlainString()
    }

    /**
     * 数字格式化，带单位
     *
     * @param number 需要格式化的数字
     */
    fun numberFormat(number: Long): String {
        return numberFormat(number.toString())
    }

    /**
     * 数字格式化，带单位
     *
     * @param number 需要格式化的数字
     */
    fun numberFormat(number: Double): String {
        return numberFormat(number.toString())
    }

    /**
     * 数字格式化，带单位
     *
     * @param number 需要格式化的数字
     */
    fun numberFormat(number: Float): String {
        return numberFormat(number.toString())
    }

    /**
     * 数字格式化，带单位
     *
     * @param number 需要格式化的数字
     */
    fun numberFormat(number: String): String {
        return numberFormat(BigDecimal(number))
    }

    /**
     * 数字格式化，带单位
     *
     * @param number 需要格式化的数字
     */
    fun numberFormatError(number: String?): String {
        if (number.isNullOrEmpty()) {
            return DEFAULT_VALUE
        }
        val bigDecimal = try {
            BigDecimal(number)
        } catch (e: Exception) {
            return DEFAULT_VALUE
        }
        return numberFormat(bigDecimal)
    }

    /**
     * 正数数字格式化，带单位
     *
     * @param positiveNumber 需要格式化的数字，需要为正数
     */
    fun positiveNumberFormat(positiveNumber: String): String {
        return numberFormat(positiveNumber)
    }

    /**
     * 负数数字格式化，带单位
     *
     * @param negativeNumber 需要格式化的数字，需要为负数数
     */
    fun negativeNumberFormat(negativeNumber: String): String {
        return numberFormat(BigDecimal(negativeNumber))
    }

    /**
     * 数字格式化，带单位
     *
     * @param bigDecimal 需要格式化的数字
     *
     * @return 小于 10000，返回原始数字，大于 10000，四舍五入保留2位小数添加单位后返回。
     */
    fun numberFormat(bigDecimal: BigDecimal): String {
        val newBigDecimal = bigDecimal.abs()
        if (newBigDecimal > BIG_DECIMAL_TRILLION) {
            return bigDecimal
                .setScale(2, BigDecimal.ROUND_HALF_UP)
                .divide(BIG_DECIMAL_TRILLION, 2, BigDecimal.ROUND_HALF_UP)
                .toPlainString() + "万亿"
        }
        if (newBigDecimal > BIG_DECIMAL_BILLION) {
            return bigDecimal
                .setScale(2, BigDecimal.ROUND_HALF_UP)
                .divide(BIG_DECIMAL_BILLION, 2, BigDecimal.ROUND_HALF_UP)
                .toPlainString() + "亿"
        }
        if (newBigDecimal > BIG_DECIMAL_TEN_THOUSAND) {
            return bigDecimal
                .setScale(2, BigDecimal.ROUND_HALF_UP)
                .divide(BIG_DECIMAL_TEN_THOUSAND, 2, BigDecimal.ROUND_HALF_UP)
                .toPlainString() + "万"
        }
        return bigDecimal.toInt().toString()
    }

    /**
     * 数字格式化，带单位
     *
     * @param bigDecimal 需要格式化的数字
     *
     * @return 小于 10000，返回原始数字，大于 10000，四舍五入保留2位小数添加单位后返回。
     */
    fun numberFormatSplit(bigDecimal: BigDecimal): FormatSplit {
        val newBigDecimal = bigDecimal.abs()
        if (newBigDecimal > BIG_DECIMAL_TRILLION) {
            val value = bigDecimal
                .setScale(2, BigDecimal.ROUND_HALF_UP)
                .divide(BIG_DECIMAL_TRILLION, 2, BigDecimal.ROUND_HALF_UP)
                .toPlainString()
            return FormatSplit(value, "万亿")
        }
        if (newBigDecimal > BIG_DECIMAL_BILLION) {
            val value = bigDecimal
                .setScale(2, BigDecimal.ROUND_HALF_UP)
                .divide(BIG_DECIMAL_BILLION, 2, BigDecimal.ROUND_HALF_UP)
                .toPlainString()
            return FormatSplit(value, "亿")
        }
        if (newBigDecimal > BIG_DECIMAL_TEN_THOUSAND) {
            val value = bigDecimal
                .setScale(2, BigDecimal.ROUND_HALF_UP)
                .divide(BIG_DECIMAL_TEN_THOUSAND, 2, BigDecimal.ROUND_HALF_UP)
                .toPlainString()
            return FormatSplit(value, "万")
        }
        return FormatSplit(bigDecimal.toInt().toString(), "")
    }

    /**
     * 价格数字格式化
     *
     * @param number 需要格式化的价格数字
     */
    fun priceNumberFormat(number: Float): String {
        return priceNumberFormat(number.toString())
    }

    /**
     * 价格数字格式化
     *
     * @param number 需要格式化的价格数字
     */
    fun priceNumberFormat(number: Double): String {
        return priceNumberFormat(number.toString())
    }

    /**
     * 价格数字格式化
     *
     * @param number 需要格式化的价格数字
     */
    fun priceNumberFormat(number: String): String {
        val bigDecimal = try {
            BigDecimal(number)
        } catch (e: NumberFormatException) {
            return "0.00"
        }
        return bigDecimal
            .setScale(2, BigDecimal.ROUND_HALF_DOWN)
            .toPlainString()
    }

    /**
     * 价格数字格式化
     *
     * @param bigDecimal 需要格式化的价格数字
     */
    fun priceNumberFormat(bigDecimal: BigDecimal, newScale: Int = 2): String {
        return bigDecimal
            .setScale(newScale, BigDecimal.ROUND_HALF_DOWN)
            .toPlainString()
    }

    /**
     * 数字转为百分比
     *
     * @param number 需要格式化的数字
     * @param withPlusSign 是否带正号
     */
    fun numberToPercentage(
        number: Double,
        withPlusSign: Boolean = true
    ): String {
        return numberToPercentage(number, 2, withPlusSign)
    }

    /**
     * 数字转为百分比
     *
     * @param number 需要格式化的数字
     * @param newScale 保留的位数
     * @param withPlusSign 是否带正号
     */
    fun numberToPercentage(
        number: Double,
        newScale: Int,
        withPlusSign: Boolean = true
    ): String {
        return numberToPercentage(number.toString(), newScale, withPlusSign)
    }

    /**
     * 数字转为百分比
     *
     * @param number 需要格式化的数字
     * @param withPlusSign 是否带正号
     */
    fun numberToPercentage(number: Float, withPlusSign: Boolean = true): String {
        return numberToPercentage(number.toString(), 2, withPlusSign)
    }

    /**
     * 数字转为百分比
     *
     * @param number 需要格式化的数字
     * @param newScale 保留的位数
     * @param withPlusSign 是否带正号
     */
    fun numberToPercentage(number: Float, newScale: Int, withPlusSign: Boolean = true): String {
        return numberToPercentage(number.toString(), newScale, withPlusSign)
    }

    /**
     * 数字转为百分比
     *
     * @param number 需要格式化的数字
     * @param newScale 保留的位数
     * @param withPlusSign 是否带正号
     */
    fun numberToPercentage(
        number: String?,
        newScale: Int = 2,
        withPlusSign: Boolean = true
    ): String {
        if (number.isNullOrEmpty()) {
            return buildString {
                append("0.")
                repeat(newScale) {
                    append("0")
                }
                append("%")
            }
        }
        val bigDecimal = try {
            BigDecimal(number)
        } catch (e: NumberFormatException) {
            return buildString {
                append("0.")
                repeat(newScale) {
                    append("0")
                }
                append("%")
            }
        }
        //返回 1 表示大于 0，返回 -1 表示小于 0
        val compareTo = bigDecimal.compareTo(BigDecimal.ZERO)
        if (withPlusSign) {
            return if (compareTo > 0) {
                "+" + privateNumberToPercentage(bigDecimal, newScale)
            } else if (compareTo <= 0) {
                "-" + privateNumberToPercentage(bigDecimal.abs(), newScale)
            } else {
                privateNumberToPercentage(bigDecimal.abs(), newScale)
            }
        }
        return privateNumberToPercentage(bigDecimal, newScale)
    }

    /**
     * 数字转为百分比
     *
     * @param number 需要格式化的数字
     * @param newScale 保留的位数
     * @param withPlusSign 是否带正号
     */
    fun numberToPercentage(
        number: BigDecimal,
        newScale: Int = 2,
        withPlusSign: Boolean = true
    ): String {
        //返回 1 表示大于 0，返回 -1 表示小于 0
        val compareTo = number.compareTo(BigDecimal.ZERO)
        if (withPlusSign && compareTo >= 0) {
            return "+" + privateNumberToPercentage(number, newScale)
        }
        return "-" + privateNumberToPercentage(number.abs(), newScale)
    }

    /**
     * 数字转为百分比。会将数字乘以100，四舍五入保留2位小数后返回。
     *
     * @param number 需要格式化的数字
     * @param newScale 保留的位数
     */
    private fun privateNumberToPercentage(number: BigDecimal, newScale: Int): String {
        return number
            .multiply(BIG_DECIMAL_HUNDRED)
            .setScale(newScale, BigDecimal.ROUND_HALF_UP)
            .toString() + "%"
    }

}